Imports System.ComponentModel
Imports Aricie.DNN.Caching
Imports Aricie.Collections
Imports Aricie.DNN.UI.Attributes
Imports Aricie.DNN
Imports Aricie.ComponentModel
Imports DotNetNuke.UI.WebControls

Namespace Aricie.DNN.Caching.Analysis
    <Serializable()> _
    Public Class CacheKeyStatistics

        Public Sub New()

        End Sub

        Public Sub New(ByVal key As String)
            Me._Key = key
        End Sub


        <NonSerialized()> _
        Public Shared StatisticsEngine As New StatisticsEngine(Of STimeSpan)(AddressOf STimeSpan.Convert, AddressOf STimeSpan.Convert)

        Private _Key As String = ""
        Private _Diagnostic As CacheDiagnostic


        'Private _IsXml As Boolean
        Private _Timings As New SerializableDictionary(Of CacheDistributionType, Series(Of STimeSpan))
        'Private _DistributionType As CacheDistributionType = CacheDistributionType.NotDistributed
        Private _IsCompressed As Boolean
        Private _PreviousKeys As New SerializableDictionary(Of String, Integer)
        Private _NextKeys As New SerializableDictionary(Of String, Integer)


        <Browsable(False)> _
        Public Property Key() As String
            Get
                Return _Key
            End Get
            Set(ByVal value As String)
                _Key = value
            End Set
        End Property



        <Category("")> _
            <MainCategory()> _
        Public ReadOnly Property SDiagnostic() As String
            Get
                Return FormatDiagnostic()
            End Get
        End Property



        <Browsable(False)> _
        Public Property Diagnostic() As CacheDiagnostic
            Get
                Return _Diagnostic
            End Get
            Set(ByVal value As CacheDiagnostic)
                Me._Diagnostic = value
            End Set
        End Property

        <Category("Statistics Detail")> _
        Public ReadOnly Property FormattedTimings() As String
            Get
                Return Me.FormatTimings(Me._Timings)
            End Get
        End Property

        '<Category("Statistics Detail")> _
        'Public Property DistributionType() As CacheDistributionType
        '    Get
        '        Return _DistributionType
        '    End Get
        '    Set(ByVal value As CacheDistributionType)
        '        _DistributionType = value
        '    End Set
        'End Property

        <Category("Statistics Detail")> _
            <IsReadOnly(True)> _
        Public Property IsCompressed() As Boolean
            Get
                Return _IsCompressed
            End Get
            Set(ByVal value As Boolean)
                _IsCompressed = value
            End Set
        End Property

        '<Category("Statistics Detail")> _
        '<IsReadOnly(True)> _
        'Public Property IsXml() As Boolean
        '    Get
        '        Return _IsXml
        '    End Get
        '    Set(ByVal value As Boolean)
        '        _IsXml = value
        '    End Set
        'End Property

        <Category("Cache Sequence")> _
        Public ReadOnly Property NbPrevKeys() As Integer
            Get
                Dim toReturn As Integer = 0
                For Each objPair As KeyValuePair(Of String, Integer) In Me.PreviousKeys
                    toReturn += objPair.Value
                Next
                Return toReturn
            End Get
        End Property

        <Category("Cache Sequence")> _
        Public ReadOnly Property FormattedPreviousKeys() As String
            Get
                Return FormatKeys(Me._PreviousKeys)
            End Get
        End Property

        <Category("Cache Sequence")> _
        Public ReadOnly Property NbNextKeys() As Integer
            Get
                Dim toReturn As Integer = 0
                For Each objPair As KeyValuePair(Of String, Integer) In Me.NextKeys
                    toReturn += objPair.Value
                Next
                Return toReturn
            End Get
        End Property

        <Category("Cache Sequence")> _
        Public ReadOnly Property FormattedNextKeys() As String
            Get
                Return FormatKeys(Me._NextKeys)
            End Get
        End Property


        <Browsable(False)> _
        Public Property Timings() As SerializableDictionary(Of CacheDistributionType, Series(Of STimeSpan))
            Get
                Return _Timings
            End Get
            Set(ByVal value As SerializableDictionary(Of CacheDistributionType, Series(Of STimeSpan)))
                _Timings = value
            End Set
        End Property

        <Browsable(False)> _
        Public Property PreviousKeys() As SerializableDictionary(Of String, Integer)
            Get
                Return _PreviousKeys
            End Get
            Set(ByVal value As SerializableDictionary(Of String, Integer))
                _PreviousKeys = value
            End Set
        End Property

        <Browsable(False)> _
        Public Property NextKeys() As SerializableDictionary(Of String, Integer)
            Get
                Return _NextKeys
            End Get
            Set(ByVal value As SerializableDictionary(Of String, Integer))
                _NextKeys = value
            End Set
        End Property




        Public Sub Merge(ByVal additionalStats As CacheKeyStatistics)

            For Each objPair As KeyValuePair(Of CacheDistributionType, Series(Of STimeSpan)) In additionalStats.Timings
                Dim objSeries As Series(Of STimeSpan) = Nothing
                If Not Me.Timings.TryGetValue(objPair.Key, objSeries) Then
                    Me.Timings(objPair.Key) = objPair.Value
                Else
                    CacheKeyStatistics.StatisticsEngine.MergeSeries(objSeries, objPair.Value)
                End If
            Next
            Dim currCount As Integer
            For Each objPair As KeyValuePair(Of String, Integer) In additionalStats.PreviousKeys
                If Not Me.PreviousKeys.TryGetValue(objPair.Key, currCount) Then
                    currCount = 0
                End If
                Me.PreviousKeys(objPair.Key) = currCount + objPair.Value
            Next
            For Each objPair As KeyValuePair(Of String, Integer) In additionalStats.NextKeys
                If Not Me.NextKeys.TryGetValue(objPair.Key, currCount) Then
                    currCount = 0
                End If
                Me.NextKeys(objPair.Key) = currCount + objPair.Value
            Next

        End Sub

        Public Function IsEmpty() As Boolean
            Return Me.Timings.Count = 0
        End Function



        Private Function FormatKeys(ByVal dico As Dictionary(Of String, Integer)) As String
            Dim toReturn As New StringBuilder
            For Each objPair As KeyValuePair(Of String, Integer) In dico
                toReturn.Append(String.Format("[Key: ""{0}"" | Count: {1}] - ", objPair.Key, objPair.Value))
            Next

            Return toReturn.ToString.Trim.TrimEnd("-"c).Trim
        End Function

        Private Function FormatTimings(ByVal timings As SerializableDictionary(Of CacheDistributionType, Series(Of STimeSpan))) As String
            Dim toReturn As String = "[Timing | Nb Samples | Avg Duration | Coef Of Variation | (Series)]"
            For Each timing As KeyValuePair(Of CacheDistributionType, Series(Of STimeSpan)) In timings
                Dim strItems As String = ""
                For Each objDuration As STimeSpan In timing.Value.Items
                    strItems &= " " & objDuration.ToString & " -"
                Next
                strItems = strItems.TrimEnd("-"c).Trim
                toReturn &= String.Format(" [{0} | {1} | {2} | +/- {3}% | ({4})] -----------", _
                                          timing.Key.ToString, _
                                          timing.Value.Items.Count.ToString, _
                                          timing.Value.Mean.ToString, _
                                          timing.Value.CoefOfVariation.ToString, _
                                          strItems)
            Next
            Return toReturn.Trim("-"c).Trim
        End Function

        Private Function FormatDiagnostic() As String
            'todo: use token replace for those
            Dim toReturn As New StringBuilder
            If Me.Diagnostic IsNot Nothing AndAlso Me.Diagnostic.SortedDistributionTypes.Count > 0 Then
                toReturn.Append("Fastest Distribution Mode: """ & Me.Diagnostic.SortedDistributionTypes(0).DistributionType.ToString)
                toReturn.Append(""" (Avg:" & Me.Diagnostic.SortedDistributionTypes(0).MeanTime.ToString & ")")
                If Me.Diagnostic.SortedDistributionTypes.Count > 1 Then
                    toReturn.Append(" | Second Available: """ & Me.Diagnostic.SortedDistributionTypes(1).DistributionType.ToString)
                    toReturn.Append(""" (Avg:" & Me.Diagnostic.SortedDistributionTypes(1).MeanTime.ToString)
                    toReturn.Append(" , " & Me.Diagnostic.SortedDistributionTypes(1).RatioToBest.ToString & " %)")
                    If Me.Diagnostic.SortedDistributionTypes.Count > 2 Then
                        toReturn.Append(" | Third Available: """ & Me.Diagnostic.SortedDistributionTypes(2).DistributionType.ToString)
                        toReturn.Append(""" (Avg:" & Me.Diagnostic.SortedDistributionTypes(2).MeanTime.ToString)
                        toReturn.Append(" , " & Me.Diagnostic.SortedDistributionTypes(2).RatioToBest.ToString & " %)")
                        If Me.Diagnostic.SortedDistributionTypes.Count > 3 Then
                            toReturn.Append(" | Fourth Available: """ & Me.Diagnostic.SortedDistributionTypes(3).DistributionType.ToString)
                            toReturn.Append(""" (Avg:" & Me.Diagnostic.SortedDistributionTypes(3).MeanTime.ToString)
                            toReturn.Append(" , " & Me.Diagnostic.SortedDistributionTypes(3).RatioToBest.ToString & " %)")
                            If Me.Diagnostic.SortedDistributionTypes.Count > 4 Then
                                toReturn.Append(" | Fifth Available: """ & Me.Diagnostic.SortedDistributionTypes(4).DistributionType.ToString)
                                toReturn.Append(""" (Avg:" & Me.Diagnostic.SortedDistributionTypes(4).MeanTime.ToString)
                                toReturn.Append(" , " & Me.Diagnostic.SortedDistributionTypes(4).RatioToBest.ToString & " %)")
                            End If
                        End If
                    End If
                End If
                If Me.PreviousKeys.Count > 0 Then
                    toReturn.Append(" | Most Frequent Previous Key: """ & Me.Diagnostic.UsualPrevKey.Key)
                    toReturn.Append("  (" & Me.Diagnostic.UsualPrevKey.SequenceFrequency & "%)")
                End If
                If Me.NextKeys.Count > 0 Then
                    toReturn.Append(" | Most Frequent Next Key: """ & Me.Diagnostic.UsualNextKey.Key)
                    toReturn.Append("  (" & Me.Diagnostic.UsualNextKey.SequenceFrequency & "%)")
                End If
            Else
                toReturn.Append("Not Enough Data")
            End If
            Return toReturn.ToString.Trim
        End Function



        Public Overrides Function ToString() As String
            Return Me.Key
        End Function



    End Class

    Public Enum StatsDiagnostic
        UnReliable
        UnDetermined
        Determined
    End Enum
End Namespace